// 用time函数做一个呼吸灯的效果

// Ensure ThreeJS is in global scope for the 'examples/'
global.THREE = require("three");

// Include any additional ThreeJS examples below
require("three/examples/js/controls/OrbitControls");

const canvasSketch = require("canvas-sketch");
const glslify = require('glslify');

const settings = {
  // Make the loop animated
  animate: true,
  // Get a WebGL canvas rather than 2D
  context: "webgl"
};

const sketch = ({ context }) => {
  // Create a renderer
  const renderer = new THREE.WebGLRenderer({
    canvas: context.canvas
  });

  // WebGL background color
  renderer.setClearColor("#fff", 1);

  // Setup a camera
  const camera = new THREE.PerspectiveCamera(50, 1, 0.01, 100);
  camera.position.set(0, 0, -4);
  camera.lookAt(new THREE.Vector3());

  // Setup camera controller
  const controls = new THREE.OrbitControls(camera, context.canvas);

  // Setup your scene
  const scene = new THREE.Scene();

  // Setup a geometry
  const geometry = new THREE.SphereGeometry(1, 100, 100);
  const baseGeom = new THREE.IcosahedronGeometry(1, 1);
  const verts = baseGeom.getAttribute('position');
  const vertsArray = verts.array;
  const circleVerts = [];
  for (let i = 0; i < vertsArray.length; i += 3) {
    const vertPosition = new THREE.Vector3(vertsArray[i], vertsArray[i + 1], vertsArray[i + 2]);
    circleVerts.push(vertPosition)
  }

  const vertexShaderSource = glslify(/* glsl */`
      varying vec2 vUv;
      varying vec3 vPosition;

      void main() {
        vPosition = position;
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xyz, 1.0);
      }
    `);
  const fragmentShaderSource = glslify(/* glsl */`
      #pragma glslify: noise = require('glsl-noise/simplex/3d');
      varying vec2 vUv;
      varying vec3 vPosition;

      uniform vec3 color;
      uniform vec3 color1;
      uniform vec3 points[POINT_COUNT];
      uniform float time;

      void main() {
        float dist = 10000.0;
        float noiseValue = 0.0;
        for (int i = 0; i < POINT_COUNT; i++) {
          vec3 icoPoint = points[i];
          float d = distance(icoPoint, vPosition);
          if (dist >= d) {
            dist = d;
            noiseValue = noise(vec3(icoPoint.x, icoPoint.y, time)) * 0.1;
          }
        }
        float mask = step(0.15 + noiseValue, dist);
        mask = 1.0 - mask;
        vec4 glFragColor = vec4(mix(color, color1, mask), 1.0);
        gl_FragColor = glFragColor;
      }
  `);

  const myShaderMaterial = new THREE.ShaderMaterial({
    transparent: true,
    defines: {
      POINT_COUNT: circleVerts.length
    },
    uniforms: {
      points: { value: circleVerts },
      color: { value: new THREE.Color('#FF3333') },
      color1: { value: new THREE.Color('#3333FF') },
      time: { value: 0 }
    },
    vertexShader: vertexShaderSource,
    fragmentShader: fragmentShaderSource
  })

  // Setup a mesh with geometry + material
  const mesh = new THREE.Mesh(geometry, myShaderMaterial);
  scene.add(mesh);

  // draw each frame
  return {
    // Handle resize events here
    resize({ pixelRatio, viewportWidth, viewportHeight }) {
      renderer.setPixelRatio(pixelRatio);
      renderer.setSize(viewportWidth, viewportHeight, false);
      camera.aspect = viewportWidth / viewportHeight;
      camera.updateProjectionMatrix();
    },
    // Update & render your scene here
    render({ time }) {
      myShaderMaterial.uniforms.time.value = time;
      controls.update();
      renderer.render(scene, camera);
    },
    // Dispose of events & renderer for cleaner hot-reloading
    unload() {
      controls.dispose();
      renderer.dispose();
    }
  };
};

canvasSketch(sketch, settings);
